home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part1 / 4147 < prev    next >
Encoding:
Text File  |  1996-08-06  |  4.7 KB  |  153 lines

  1. Path: newspost1.alt.net!usenet
  2. From: walth@netcom.com (Walt Howard)
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: Copy constructing an already default constructed object
  5. Date: Sun, 28 Jan 1996 12:58:44 GMT
  6. Organization: AltNet - Affordable Usenet Access - http://www.alt.net
  7. Message-ID: <4efruf$elb@tofu.alt.net>
  8. References: <4e906b$stk@elaine32.Stanford.EDU> <ENNO.96Jan26221035@kitz.inferenzsysteme.informatik.th-darmstadt.de>
  9. Reply-To: walth@netcom.com
  10. X-Newsreader: Forte Agent .99c/32.126
  11.  
  12. On 26 Jan 1996 21:10:35 GMT,
  13. enno@inferenzsysteme.informatik.th-darmstadt.de (Enno Sandner) wrote:
  14.  
  15. >In article <4e906b$stk@elaine32.Stanford.EDU> brien@leland.Stanford.EDU (brien oberstein) writes:
  16. >
  17. >   I'd like to get some opinions on the best/cleanest way
  18. >   to accomplish the following:
  19. >
  20. >   I've got an object which has already been constructed
  21. >   via its default constructor which just sets all pointers
  22. >   to NULL.  Whats the best way to deep-copy into it?
  23. >
  24. >
  25. >   class A {
  26. >   public:
  27. >     A();             // default ctor
  28. >     A(const A&)      // copy ctor
  29. >     A(const char *)  // convert ctor 
  30. >   }; 
  31. >
  32. >   somefunc()
  33. >   {
  34. >     ...
  35. >     A a0;
  36. >     ...
  37. >     A a1("blah");
  38. >
  39. >     //
  40. >     // How do you deep copy a1 into a0 ???
  41. >     //
  42. >     a0 = a1;         // no good. shallow copy
  43. >     a0 = A(a1);         // no good. dtor called for temp A object
  44. >     a0 = *new A(a1);   // no good. creates memory for a A object
  45. >
  46. >     //
  47. >     // the follow works but is tedious
  48. >     //
  49. >     A empty;         // create an empty object
  50. >     A tmp(a1);         // deep-copy a1 to temp
  51.  
  52. Here you are using a copy constructor. How is the copy constructor
  53. doing a deep copy? Use that logic here!
  54.  
  55. >     a0 = tmp;         // shallow-copy temp to a0
  56. >     tmp = empty;         // clear out temp so internals are not destructed
  57. >
  58. >     //
  59. >     // so overload = to make deep copies
  60. >     //
  61. >     a0 = a1;
  62. >
  63. >   }
  64. >
  65. >   //
  66. >   // deep-copy =
  67. >   //
  68. >   A& A::operator =(const A& other)
  69. >   {
  70. >     A empty;
  71. >     A tmp(other);
  72. >     memcpy(this, &tmp, sizeof(A));
  73. >     memcpy(&tmp, &empty, sizeof(A));
  74. >     return *this;
  75. >   }
  76. >
  77. >
  78.  
  79. One thing I do is to avoid unecessary pointers. For example so often
  80. the pointers point to strings or memory buffers you should just create
  81. a simple class of string and simple class of memory buffer that you
  82. put into the object so you don't have to have a pointer. Copy
  83. construction and assignment then work automatically.
  84.  
  85. class NeedsCustomWrittenAssignmentOperator
  86. {
  87.     char* contents;
  88. };
  89.  
  90. class DefaultAssignmentOperatorWorksFine
  91. {
  92.     memorybuffer contents;  // (memory buffer is a class)
  93. };
  94.  
  95. Because assignment of a whole object is done by assignment of its
  96. individual members, the second class doesn't need to have
  97. an assignment operator written.
  98.  
  99. Now somewhere along the line you are going to have to deal with a
  100. pointer to a block of memory. That you do WITHIN the memorybuffer
  101. object and do it really well, ONCE AND FOR ALL. Now you can use that
  102. work you put into taming pointers without danger of making a mistake.
  103. You can use your brainpower on more important things.
  104.  
  105. AND if you want the memorybuffer to LOOK like a memory buffer, you
  106. just declare an: operator char*() function that returns the actual
  107. memory address that memorybuffer is managing. It will look JUST like
  108. the old kind of malloc'ed memory, but has an object around it to deal
  109. with copying, construction and destruction.
  110.  
  111. Pointers, though sometimes necessary, carry a HEAVY price. They 
  112. introduce dependencies upon:
  113.  
  114. 1) Memory layout
  115. 2) Referents - the pointer and the pointee are now bound together in
  116. an inflexible construct.
  117.  
  118. which results in
  119.  
  120. 3) The objects involved begin to act like ONE large object.
  121.  
  122. and thus losing the flexibility you might have been trying to achieve
  123. by using objects.
  124.  
  125. >   I'd like to know what people think of the solution I've reached.
  126. >   I figure that this type of shit is common enough so there should 
  127. >   be some widely accepted solution to this problem.  Or maybe its
  128. >   not, but believe me that the situation does occur.
  129. >
  130. >A class should define its copy-semantics, not the clients of that class.
  131. >Often assignment can be expressed in terms of destruction and copy-
  132. >construction, ie.
  133. >
  134. >        Class& operator = (const Class& c) {
  135. >           if (this!=&c) {
  136. >              this->~Class();       // cleanup
  137. >              new (this) Class(c);  // perform copy-construction
  138. >           }
  139. >           return *this;
  140. >        }
  141. >
  142. >In this case the constructor, destructor and copy-constructor are
  143. >enough to determine the copy-semantics of the class. If a deep-copy
  144. >is needed _you_ have to provide a suitable implementation for them.
  145. >BTW performing a bitwise-copy using 'memcpy' is usually a bad idea.
  146.  
  147. Yeah. It's late. G'nite
  148.  
  149. >
  150. >        Enno
  151.  
  152.  
  153.